package com.chalk.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.chalk.common.constant.CommonConstants;
import com.chalk.common.constant.SecurityConstants;
import com.chalk.common.constant.StatusConstants;
import com.chalk.common.exception.ServiceException;
import com.chalk.common.pay.ali.AliPayUtil;
import com.chalk.common.pay.wx.WxPayUtil;
import com.chalk.common.util.*;
import com.chalk.config.base.BaseController;
import com.chalk.config.security.JwtRedisUtil;
import com.chalk.config.security.JwtTokenUtils;
import com.chalk.config.security.SecurityPasswordUtil;
import com.chalk.dto.WxUserDto;
import com.chalk.model.Member;
import com.chalk.model.SysUser;
import com.chalk.model.SysUserRoleRelated;
import com.chalk.service.MemberService;
import com.chalk.service.SysUserRoleRelatedService;
import com.chalk.service.SysUserService;
import com.chalk.util.ImgUtil;

import com.chalk.vo.TokenVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.DocumentException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @date: 2019-04-02 上午 11:19
 * @author: zhaobo0119@outlook.com
 * @Descriptopn:
 */
@Api(value = "登陆/注册/短信验证接口", tags = "登陆/注册/短信验证模块")
@RestController
@RequestMapping("/ignoreAuth")
public class IgnoreAuthController extends BaseController {

    /**
     * 短信验证码redis保存头
     */
   /* @Value("${aliyun.sms.redis-head}")
    private String SMS_REDIS_HEAD;*/
    /**
     * 短信验证码过期时间
     */
    @Value("${aliyun.sms.expire-time}")
    private long SMS_REDIS_EXPIRE_TIME;
    @Value("${upload.dir}")
    String dir;

    @Value("${ip.addr}")
    String addr;

    @Value("${app.apk}")
    String filePath;

    /**
     * 短信验证码模板
     */
    @Value("${aliyun.sms.verification-code-template}")
    private String verificationCodeTemplate;

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MemberService memberService;
    @Autowired
    private JwtRedisUtil jwtRedisUtil;


    @Autowired
    SysUserService sysUserService;


    @Autowired
    private SysUserRoleRelatedService relatedService;

    /**
     * 发送手机验证码
     *
     * @param phoneNumber 手机号
     * @return 验证码
     * @throws Exception
     */
    /*@ApiOperation(value = "发送手机验证码", notes = "发送手机验证码", response = Result.class)
    @PostMapping("/sendSmsCode/{phoneNumber}")
    public Result sendSmsCode(
            @ApiParam(name = "phoneNumber", value = "手机号码", required = true, example = "18888888888")
            @PathVariable("phoneNumber") String phoneNumber) throws Exception {
        *//* 校验手机号 *//*
        if (!CommonUtil.isPhoneNumber(phoneNumber)) {
            return Result.fail("手机号码不正确");
        }
        ;
        *//* 随机验证码 *//*
        String smsCode = CommonUtil.smsCode();
        *//* 发送验证码 *//*
        boolean result = AliSmsClient.sendSmsCode(phoneNumber, smsCode, verificationCodeTemplate);
        System.out.println(SMS_REDIS_HEAD);
        if (result) {
            redisUtil.set(SMS_REDIS_HEAD + phoneNumber, smsCode, SMS_REDIS_EXPIRE_TIME);
            return Result.success("验证码发送成功");
        }
        return Result.fail("验证码发送失败");
    }

    @ApiOperation(value = "发送手机验证码", notes = "发送手机验证码", response = Result.class)
    @PostMapping("/sendSmsCodeByPassword/{phoneNumber}")
    public Result sendSmsCodeByPassword(
            @ApiParam(name = "phoneNumber", value = "手机号码", required = true, example = "18888888888")
            @PathVariable("phoneNumber") String phoneNumber) throws Exception {
        *//* 校验手机号 *//*
        if (!CommonUtil.isPhoneNumber(phoneNumber)) {
            return Result.fail("手机号码不正确");
        }
        ;
        *//* 随机验证码 *//*
        String smsCode = CommonUtil.smsCode();
        *//* 发送验证码 *//*
        boolean result = AliSmsClient.sendSmsCode(phoneNumber, smsCode, verificationCodeTemplate);
        if (result) {
            redisUtil.set(SMS_REDIS_HEAD+ "pwd" + phoneNumber, smsCode, SMS_REDIS_EXPIRE_TIME);
            return Result.success("验证码发送成功");
        }
        return Result.fail("验证码发送失败");
    }*/

    /**
     * 验证手机号码是否已注册
     *
     * @param phoneNumber 手机号
     * @return 验证码 注册验证
     * 注册验证
     * Registration verification
     * @throws Exception
     */
    /*@ApiOperation(value = "验证手机号码是否已注册(10012:未注册 10013:已注册)", notes = "发送手机验证码", response = Result.class)
    @PostMapping("/registrationVerification/{phoneNumber}")
    public Result registrationVerification(
            @ApiParam(name = "phoneNumber", value = "手机号码", required = true, example = "18888888888")
            @PathVariable("phoneNumber") String phoneNumber) throws Exception {
        *//* 校验手机号 *//*
        if (!CommonUtil.isPhoneNumber(phoneNumber)) {
            return Result.fail("手机号码不正确");
        }
        ;
        *//* 验证手机号是否已注册 *//*
        int count = memberService.selectCount(new EntityWrapper<Member>()
                .eq("mobile_phone", phoneNumber)
                .eq("is_deleted", CommonConstants.IsDeleted.NOTDEL.getValue()));
        if (count == 0) {
            return Result.success(ResultCode.PHONE_NOT_REG, phoneNumber);
        }
        return Result.success(ResultCode.PHONE_REG_ED, phoneNumber);
    }*/

    /**
     * 用户注册
     *
     * @param phoneNumber 手机号
     * @param password    密码
     *                    //* @param code        短信验证码
     * @return
     */
    @ApiOperation(value = "用户注册", notes = "用户注册", response = Result.class)
    @PostMapping("/register/{phoneNumber}/{password}")
    public Result register(
            @ApiParam(name = "phoneNumber", value = "手机号", required = true)
            @PathVariable("phoneNumber") String phoneNumber,
            @ApiParam(name = "password", value = "密码", required = true)
            @PathVariable("password") String password,
            String referrer) {
        Map<Object, Object> params = new HashMap<Object, Object>();
        if (StringUtils.isBlank(phoneNumber) || StringUtils.isBlank(password) /*|| StringUtils.isBlank(code)*/) {
            return Result.fail("手机号、密码、验证码不能为空");
        }
        if (password.length() < CommonConstants.APP_USER_PWD_MIN_LEN || password.length() > CommonConstants.APP_USER_PWD_MAX_LEN) {
            return Result.fail("密码长度为6-16位");
        }
        /* 判断验证码 */
        String smsCode = redisUtil.get(phoneNumber, String.class);
        int count = this.ValidSms(phoneNumber);
        if (count != 0) {
            return Result.fail("该手机号码已注册");
        }
        Member member = new Member();
        member.setMobilePhone(phoneNumber);
        if (StringUtils.isNotEmpty(referrer)) {
            String signUserId = JwtTokenUtils.solutionUserId(referrer);
            member.setReferenceId(signUserId);
        }
        // bcrypt 加密
        member.setPassword(SecurityPasswordUtil.md5Encrypt(password));
        memberService.insert(member);
        return Result.success("注册成功");
    }

    /**
     * 忘记密码
     *
     * @param phoneNumber 手机号
     * @param password    密码
     * @param code        验证码
     * @return
     */
    @ApiOperation(value = "忘记密码", notes = "忘记密码", response = Result.class)
    @GetMapping("/findPwd/{phoneNumber}/{password}/{code}")
    public Result findPwd(
            @ApiParam(name = "phoneNumber", value = "手机号", required = true)
            @PathVariable("phoneNumber") String phoneNumber,
            @ApiParam(name = "password", value = "新密码", required = true)
            @PathVariable("password") String password,
            @ApiParam(name = "code", value = "验证码", required = true)
            @PathVariable("code") String code
    ) {
        /* 验证手机号是否已注册 */
        Member member = memberService.selectOne(new EntityWrapper<Member>()
                .eq("mobile_phone", phoneNumber)
                .eq("is_deleted", CommonConstants.IsDeleted.NOTDEL.getValue()));
        if (member == null) {
            return Result.fail("账号无效");
        }
        String smsCode = redisUtil.get("pwd" + phoneNumber, String.class);
        if (StringUtils.isBlank(smsCode)) {
            throw new ServiceException(ResultCode.SMS_CODE_EXP);
        }
        if (!smsCode.equals(code)) {
            throw new ServiceException(ResultCode.SMS_CODE_ERROR);
        } else {
            redisUtil.delete("pwd" + phoneNumber);
            member.setPassword(SecurityPasswordUtil.md5Encrypt(password));
            member.setUpdateTime(DateUtil.date());
            memberService.updateById(member);
            return Result.success();
        }
    }

    /**
     * 用户密码登录
     *
     * @param member 实体类
     * @param
     * @return
     */
    @ApiOperation(value = "用户密码登录", notes = "用户密码登录", response = Result.class)
    @PostMapping("/loginforpassword")
    public Result PwdLogin(@RequestBody @Valid Member member) {
        Member member1 = memberService.getMemberByMobilePhone(member.getMobilePhone());
        if (member1 == null) {
            throw new ServiceException(ResultCode.LOG_ERROR);
        }
        /* 判断密码是否正确 */
        if (!SecurityPasswordUtil.md5Encrypt(member.getPassword()).equals(member1.getPassword())) {
            throw new ServiceException(ResultCode.LOG_ERROR);
        }
        String token = jwtRedisUtil.createRedisToken(member.getMobilePhone(), SecurityConstants.ROLE_LOGIN);
        /* 返回token */

        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        if (member1.getDistributorId() != null) {
            map.put("type", member1.getDistributorId());
        } else {
            map.put("type", member1.getMemberType());
        }

        return Result.success(ResultCode.SUCCESS.msg(), map);
    }

    /**
     * 用户短信登录
     *
     * @param phoneNumber 手机号
     *                    //* @param code        短信验证码
     * @return
     */
    @ApiOperation(value = "用户短信登录", notes = "用户短信登录", response = Result.class)
    @PostMapping("/login/{phoneNumber}/{code}")
    public Result SmsLogin(
            @ApiParam(name = "phoneNumber", value = "手机号", required = true)
            @PathVariable("phoneNumber") String phoneNumber/*,
            @ApiParam(name = "code", value = "验证码", required = true)
            @PathVariable("code") String code*/) {
        /* 判断验证码 */
        String smsCode = redisUtil.get(phoneNumber, String.class);
        int count = this.ValidSms(phoneNumber);
        if (count == 0) {
            throw new ServiceException(ResultCode.PHONE_NOT_REG);
        }
        String token = jwtRedisUtil.createRedisToken(phoneNumber, SecurityConstants.ROLE_LOGIN);
        /* 返回token */
        return Result.success(ResultCode.SUCCESS.msg(), token);
    }

    /**
     * 小程序openId登录
     *
     * @param wxUserDto
     * @return
     */
    @ApiOperation(value = "openId登录", notes = "openId登录", response = Result.class)
    @PostMapping("/openIdLogin")
    public Result openIdLogin(@RequestBody @Valid WxUserDto wxUserDto, BindingResult bindingResult) {
        super.beanValidator(bindingResult);
        Member params = new Member();
        DateTime date = DateUtil.date();
        params.setOpenId(wxUserDto.getOpenId());
        Member member = memberService.selectOne(new EntityWrapper<>(params));
        if (member == null) {
            params.setCreateTime(date);
            params.setUpdateTime(date);
            params.setNickName(wxUserDto.getNickname());
            params.setPicUrl(wxUserDto.getPicUrl());
            boolean result = memberService.insert(params);
            if (result) {
                Map<String, Object> tokenAndRefreshToken = jwtRedisUtil.getTokenAndRefreshToken(wxUserDto.getOpenId(), SecurityConstants.ROLE_LOGIN);
                return Result.success(tokenAndRefreshToken);
            }
        }
        // 判断用户状态
        if (CommonConstants.IsDeleted.NOTDEL.getValue().equals(member.getIsDeleted())) {
            Map<String, Object> tokenAndRefreshToken = jwtRedisUtil.getTokenAndRefreshToken(wxUserDto.getOpenId(), SecurityConstants.ROLE_LOGIN);
            return Result.success(tokenAndRefreshToken);

        }
        return Result.fail("用户信息已被清除");
    }

    /**
     * 短信验证码验证
     *
     * @param phoneNumber 手机号
     *                    //* @param smsCode     接收到的短信验证码
     */
    @ApiOperation(value = "短信验证码验证", notes = "短信验证码验证", response = Result.class)
    @GetMapping("/validSmsCode")
    public Result validSmsCode(String phoneNumber) {
        String code = redisUtil.get(phoneNumber, String.class);
        if (StringUtils.isBlank(code)) {
            throw new ServiceException(ResultCode.SMS_CODE_EXP);
        }
        /*if (!smsCode.equals(code)) {
            throw new ServiceException(ResultCode.SMS_CODE_ERROR);
        }*/
        /* 销毁验证码(验证通过则销毁，防止多次使用) */
        redisUtil.delete(phoneNumber);
        return Result.success();
    }

    /**
     * 短信验证码验证
     *
     * @param phoneNumber 手机号
     *                    //* @param code        接收到的短信验证码
     *                    //* @param smsCode     缓存中的验证码
     */
    private int ValidSms(String phoneNumber) {
        /*if (StringUtils.isBlank(smsCode)) {
            throw new ServiceException(ResultCode.SMS_CODE_EXP);
        }
        if (!smsCode.equals(code)) {
            throw new ServiceException(ResultCode.SMS_CODE_ERROR);
        }*/
        /* 销毁验证码(验证通过则销毁，防止多次使用) */
        redisUtil.delete(phoneNumber);
        int count = memberService.selectCount(new EntityWrapper<Member>()
                .eq("mobile_phone", phoneNumber)
                .eq("is_deleted", CommonConstants.IsDeleted.NOTDEL.getValue()));
        return count;
    }





    /**
     * 刷新token
     *
     * @return 验证码 注册验证
     * 注册验证
     * Registration verification
     * @throws Exception
     */
    @ApiOperation(value = "刷新token", notes = "刷新token", response = Result.class)
    @PostMapping("/refreshToken")
    public Result getTokenForRefreshTOken(@RequestBody Map<String, String> map) throws Exception {
        String refresh = map.get("refresh");
        TokenVo vo = jwtRedisUtil.CompRefreshToken(refresh);
        if (vo.getCode() == 1) {
            return Result.success(vo);
        } else {
            return Result.fail("无效的令牌");
        }
    }





    /**
     * 上传文件
     * @param file
     * @return
     */
    @ApiOperation(value = "上传文件", notes = "上传文件", response = Result.class)
    @PostMapping("uploadFile")
    public Result uploadFile(@RequestParam(value = "file") MultipartFile file)throws IOException{
        //需要返回的消息
       Map<String,Object> data = new HashMap<>();
        if( !file.isEmpty()) {

            //上传目录
            String uploadPath = dir + "/img/";
            //验证图片后缀
            String suffix= ImgUtil.splitImg(file.getOriginalFilename());
            //图片名称
            String imgName=System.currentTimeMillis() + "." + suffix;
            if(ImgUtil.checkImg(suffix)) {
                File upFile = new File(uploadPath ,imgName);
                if (!upFile.exists()) {
                    upFile.createNewFile();
                } else {
                    upFile.delete();
                }
                System.out.println(upFile.getAbsoluteFile());
                file.transferTo(upFile.getAbsoluteFile());
                data.put("msg","上传成功");
                data.put("imgUrl",addr+"upload/img/"+imgName);


            }
            else {
                data.put("msg","图片格式错误，请上传jpg/png/gif格式的图片");
            }



        }else {
            data.put("msg","图片不能为空！");
        }

     return  Result.success(data);

    }

    /**
     * 下载软件apk
     * @return
     * @throws IOException
     */
    @RequestMapping("downloadApk")
    public ResponseEntity<InputStreamSource> downloadApk() throws IOException{
        FileSystemResource file = new FileSystemResource(filePath);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", file.getFilename()));
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");

        return ResponseEntity
                .ok()
                .headers(headers)
                .contentLength(file.contentLength())
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .body(new InputStreamResource(file.getInputStream()));
    }


}

